/*********************************************************************************
 *      Copyright:  (C) 2025 HuangXiangming<huangxaingming@163.com>
 *                  All rights reserved.
 *
 *       Filename:  server_function.c
 *    Description:  This file is about server connect function
 *                 
 *        Version:  1.0.0(25/03/25)
 *         Author:  Huang Xiangming <huangxiangming@163.com>
 *      ChangeLog:  1, Release initial version on "25/04/3 12:23:02"
 *                 
 ********************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/resource.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "server_function.h"
#include "logger.h"

int socket_server_init(char *listen_ip, int listen_port)
{
	struct sockaddr_in      servaddr;
	int                     rv = 0;
	int                     on = 1;
	int                     listenfd;

	if ( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
	{
		log_warn("Use socket() to create a TCP socket failure: %s\n", strerror(errno));
		return -1;
	}
	setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(listen_port);

	if ( !listen_ip )
	{
		servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	}
	else
	{
		if ( inet_pton(AF_INET, listen_ip, &servaddr.sin_addr) <= 0 )
		{
			log_warn("inet_pton() set listen IP address failure.\n");
			rv = -2;
			goto CleanUp;
		}
	}
	if ( bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0 )
	{
		log_warn("Use bind() to bind the TCP socket failure: %s\n", strerror(errno));
		rv = -3;
		goto CleanUp;
	}

	if ( listen(listenfd, 64) < 0 )
	{
		log_warn("Use bind() to bind the TCP socket: %s\n", strerror(errno));
		rv = -4;
		goto CleanUp;
	}
CleanUp:
	if(rv < 0)
		close(listenfd);
	else
		rv = listenfd;

	return rv;
	
}


void set_socket_rlimit(void)
{
	struct rlimit limit = {0};

	getrlimit(RLIMIT_NOFILE, &limit);
	limit.rlim_cur = limit.rlim_max;
	setrlimit(RLIMIT_NOFILE, &limit);

	log_info("set socket open fd max count to %d\n", limit.rlim_max);

}

int parse_data(uint8_t *buf, data_t *data)
{
	int         k = 0;
	char        *str = NULL;
	
	if( !buf || !data )
	{
		log_warn("arguments is NULL");
		return -1;
	}

	str = strtok(buf, "=");
	while ( str )
	{   
		str = strtok(NULL, "\n");
		if ( k == 0 )
		{
			snprintf(data->id, sizeof(data->id), "%s", str);
		}
		else if ( k == 1 )
		{
			snprintf(data->sample_time, sizeof(data->sample_time), "%s", str);
		}
		else if ( k == 2)
		{
			
			float 		temp_value = atof(str);
			snprintf(data->temp, sizeof(data->temp), "%.4f", temp_value);
		}
		++k;
		str = strtok(NULL, "=");
	}

	k = 0;
	return 0;
}

int parse_data_json(uint8_t *buf, data_t *data)
{
	int			k = 0;
	char		*str = NULL;

	if( !buf || !data )
	{
		log_warn("arguments is NULL");
		return -1;
	}

	str = strtok(buf, ":");
	while ( str )
	{
		str = strtok(NULL, "\"");
		if ( k == 0 )   
		{               
			snprintf(data->id, sizeof(data->id), "%s", str);
		}               
		else if (k == 1 )
		{               
			snprintf(data->sample_time, sizeof(data->sample_time), "%s", str);
		}               
		else if (k == 2)
		{ 
			float 		temp_value = atof(str);
			snprintf(data->temp, sizeof(data->temp), "%.4f", temp_value);
		}
		++k;
		str = strtok(NULL, ":");
	}

	k = 0;
	return 0;
}

int parse_data_tlv(uint8_t *buf, data_t *data) 
{
	char        *str = NULL;
	char 		temp_str[32];
	int			tag_temperature = 1;
	uint16_t    crc_check;

	if( !buf || !data )
	{
		log_warn("arguments is NULL");
		return -1;
	}

	//Header
	uint16_t header = ntohs(*(uint16_t *)buf);
	if ( header != 0xFEDD )
	{
		log_error("Header failure\n");
		return -1;
	}

	//Tag
	uint8_t tag = buf[2];
	if ( tag != tag_temperature )
	{
		log_error("Tag failure\n");
		return -1;
	}

	//Length
	uint16_t length = (*(uint16_t *)(buf + 3));

	//Valure:ID
	char id[10] = {0};
	memcpy(id, buf + 5, 10);

	//Valure:TIME
	uint8_t year = buf[15];     		// 年 - 2000
	uint8_t month = buf[16];    		// 月
	uint8_t day = buf[17];      		// 日
	uint8_t hour = buf[18];     		// 时
	uint8_t minute = buf[19];   		// 分
	uint8_t second = buf[20];   		// 秒

	uint8_t temp_int = buf[21];            // 整数部分
	uint8_t temp_decimal1 = buf[22]; // 小数部分 ×10000
	uint8_t temp_decimal2 = buf[23]; // 小数部分 ×10000

	//CRC校验
	uint16_t crc = ntohs(*(uint16_t *)(buf + 24));
	crc_check = crc_itu_t(buf, length+5);
	if ( crc != crc_check )
	{
		log_error("CRC failure\nCRC16: 0x%04X\nCRC16_check: 0x%04X\n", crc, crc_check);
		return -1;
	}

	strncpy(data->id, id, sizeof(data->id));
	snprintf(data->sample_time, sizeof(data->sample_time), 
			"%04d%02d%02d %02d:%02d:%02d",year + 2000, month, day, hour, minute, second);
	snprintf(data->temp, sizeof(data->temp), "%d.%02d%02d", temp_int, temp_decimal1, temp_decimal2);

	return 0;
}

static uint16_t crc_itu_t(const uint8_t *data, size_t length)
{
	uint16_t          crc = 0xFFFF;
	size_t            i, j;
	 
	for (i=0; i<length; i++)
	{
		crc ^= ((uint16_t)data[i] << 8);

		for(j=0; j<8; j++)
		{
			if (crc & 0x8000)
			{
				crc = (crc << 1) ^ CRC16_ITU_T_POLY;
			}
			else
			{
				crc <<= 1;
			}
		}
	}

	return crc;
}
